#include "iConfig.hpp"

#if GLF_ENABLE_DEBUGGER

#include <glf/debugger/xml.h>

namespace glf
{
namespace debugger
{
	
inline const char* rfindbound(const char* str)
{
	while(*str == ' ')
		str--;
	return str;
}

inline const char* rfindchar(const char* str, int ch)
{
	while(*str != ch)
		str--;
	return str;
}

bool XmlReader::ParseTag(StringMap& tagAttr, const char* tagBuffer)
{
	if(tagBuffer[0] == '/')
		return false;
	
	const char* sep = strchr(tagBuffer, ' ');
	if(!sep)
		sep = strchr(tagBuffer, '/');
	if(!sep)
		sep = tagBuffer + strlen(tagBuffer);
	std::string tag_name(tagBuffer, sep - tagBuffer);
	tagAttr["<id>"] = tag_name;

	const char* eq = strstr(tagBuffer, "=");
	while(eq)
	{
		const char* endname = rfindbound(eq);
		if(!endname)
			return false;
		const char* startname = rfindchar(eq, ' ');
		if(!startname)
			return false;
		const char* startvalueQuote = strchr(eq, '\"');
		const char* startvalueApp = strchr(eq, '\'');
		if(!startvalueQuote && !startvalueApp)
			return false;
		const char* startvalue = startvalueQuote;
		if(startvalueQuote && startvalueApp)
			startvalue = startvalueQuote < startvalueApp ? startvalueQuote : startvalueApp;
		else if(startvalueApp)
			startvalue = startvalueApp;
		const char* endvalue = strchr(startvalue + 1, *startvalue);
		if(!endvalue)
			return false;

		std::string name(startname + 1, endname - startname - 1);
		std::string value(startvalue + 1, endvalue - startvalue - 1);
		tagAttr[name] = value;

		eq = strstr(endvalue, "=");
	}

	return true;
}

void XmlReader::Parse(const std::string& xml)
{
	const char* buffer = xml.c_str();
	for(uint i = 0; i < xml.size();)
	{
		if(buffer[i] == '<')
		{
			const char* end = strstr(&buffer[i], ">");
			if(end == NULL || i + 1 >= xml.size())
				break;

			// closing tag?
			if(buffer[i + 1] == '/')
			{
				const char* begin = &buffer[i + 2];
				end = strstr(begin, ">");
				if(end != NULL)
				{
					std::string tagName(begin, end - begin);
					mHandler->EndTag(tagName);
				}
			}
			else if(buffer[i + 1] == '?')
			{
				//end = strstr(&buffer[i + 2], "?");
				//if(end == NULL || i + 1 >= xml.size())
				//	break;
				//i = end - buffer[i] + 2;
			}
			else
			{
				std::string tagBuffer(&buffer[i + 1], end - &buffer[i] - 1);

				// parse tag and convert to attributes
				StringMap tag;
				ParseTag(tag, tagBuffer.c_str());

				// create style using current as base attributes
				//EditTextCharacter::TextAttributes attr;
				//attr = m_attributes_stack.back();
				StringMap::const_iterator it = tag.find("<id>");
				if(it != tag.end())
				{
					std::string id = it->second;
					mHandler->BeginTag(tag);
				}
			}
			i = end - buffer + 1;
		}
		else
		{
			const char* end = strstr(&buffer[i], "<");
			bool buffer_end = end == NULL;
			if(buffer_end)
				end = buffer + xml.size();
			
			if(buffer_end)
				break;
			
			i = end - buffer;
		}
	}
}

XmlWriter::XmlWriter()
{
	mXml = "<?xml version=\"1.0\"?>\n";
}

void XmlWriter::BeginTag(const std::string& id)
{
	StringPairVector empty;
	BeginTag(id, empty);
}

void XmlWriter::BeginTag(const std::string& id, StringPairVector& tagAttr)
{
	//for(uint i = 0; i < mStack.size(); i++)
	//	mXml += "\t";

	if(mStack.size() > 0)
	{
		if(!mStack.back().mChild)
			mXml += ">\n";
		
		mStack.back().mChild = true;
	}

	Tag tag;
	tag.mChild = false;
	tag.mId = id;
	mStack.push_back(tag);

	mXml += "<";
	mXml += tag.mId;
	mXml += " ";
	
	for(StringPairVector::const_iterator it = tagAttr.begin(); it != tagAttr.end(); ++it)
	{
		mXml += it->first;
		mXml += "=\"";
		mXml += it->second;
		mXml += "\" ";
	}
}

void XmlWriter::EndTag()
{
	Tag& tag = mStack.back();

	if(tag.mChild)
	{
		//for(uint i = 0; i < mStack.size() - 1; i++)
		//	mXml += "\t";

		mXml += "</";
		mXml += tag.mId;
		mXml += ">\n";
	}
	else
	{
		mXml += "/>\n";
	}

	mStack.pop_back();
}

} //namespace debugger
} //namespace glf

#endif // GLF_ENABLE_DEBUGGER
